home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 February / EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso / earcd / comm2 / termsorc.lha / Extras / Source / term-source.lha / termLocale.c < prev    next >
C/C++ Source or Header  |  1995-09-26  |  17KB  |  902 lines

  1. /*
  2. **    termLocale.c
  3. **
  4. **    Localization support routines
  5. **
  6. **    Copyright © 1990-1995 by Olaf `Olsen' Barthel
  7. **        All Rights Reserved
  8. */
  9.  
  10. #include "termGlobal.h"
  11.  
  12.     /* The catalog data is stored in the following format. */
  13.  
  14. struct CatCompArrayType
  15. {
  16.     LONG    cca_ID;
  17.     STRPTR    cca_Str;
  18. };
  19.  
  20. extern struct CatCompArrayType    *AppStrings;
  21. extern LONG             NumAppStrings;
  22.  
  23.     /* LocaleOpen(STRPTR CatalogName,STRPTR BuiltIn):
  24.      *
  25.      *    Open string translation tables.
  26.      */
  27.  
  28. VOID __regargs
  29. LocaleOpen(STRPTR CatalogName,STRPTR BuiltIn,LONG Version)
  30. {
  31.     if(LocaleBase = (struct LocaleBase *)OpenLibrary("locale.library",38))
  32.     {
  33.         if(LocaleBase -> lb_SysPatches)
  34.         {
  35.             strcpy(ConvNumber,"%lD");
  36.             strcpy(ConvNumber10,"%10lD");
  37.  
  38.             if(Catalog = OpenCatalog(NULL,CatalogName,
  39.                 OC_BuiltInLanguage,    BuiltIn,
  40.                 OC_BuiltInCodeSet,    0,
  41.  
  42.                 Language[0] ? OC_Language : TAG_IGNORE,Language,
  43.             TAG_DONE))
  44.             {
  45.                 BOOL TooOld = FALSE;
  46.  
  47.                     // Don't load an outdated catalog file
  48.  
  49.                 if(Catalog -> cat_Version < Version)
  50.                     TooOld = TRUE;
  51.                 else
  52.                 {
  53.                     if(strcmp(GetCatalogStr(Catalog,MSG_OFFSET_TEST1_TXT,""),"v4.0"))
  54.                         TooOld = TRUE;
  55.                 }
  56.  
  57.                 if(TooOld)
  58.                 {
  59.                     if(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0))
  60.                     {
  61.                         MyEasyRequest(NULL,"The catalog file is too old to be used\nwith this `term' revision.","Continue");
  62.  
  63.                         CloseLibrary(IntuitionBase);
  64.  
  65.                         IntuitionBase = NULL;
  66.                     }
  67.  
  68.                     CloseCatalog(Catalog);
  69.  
  70.                     Catalog = NULL;
  71.                 }
  72.             }
  73.  
  74.             Locale = OpenLocale(NULL);
  75.         }
  76.         else
  77.         {
  78.             if(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0))
  79.             {
  80.                 MyEasyRequest(NULL,"Your \"locale.library\" is not installed correctly.","Continue");
  81.  
  82.                 CloseLibrary(IntuitionBase);
  83.  
  84.                 IntuitionBase = NULL;
  85.             }
  86.  
  87.             strcpy(ConvNumber,"%ld");
  88.             strcpy(ConvNumber10,"%10ld");
  89.  
  90.             CloseLibrary(LocaleBase);
  91.  
  92.             LocaleBase = NULL;
  93.         }
  94.     }
  95.     else
  96.     {
  97.         strcpy(ConvNumber,"%ld");
  98.         strcpy(ConvNumber10,"%10ld");
  99.     }
  100. }
  101.  
  102.     /* LocaleClose():
  103.      *
  104.      *    Close the translation tables.
  105.      */
  106.  
  107. VOID
  108. LocaleClose()
  109. {
  110.     if(Locale)
  111.     {
  112.         CloseLocale(Locale);
  113.  
  114.         Locale = NULL;
  115.     }
  116.  
  117.     if(Catalog)
  118.     {
  119.         CloseCatalog(Catalog);
  120.  
  121.         Catalog = NULL;
  122.     }
  123.  
  124.     if(LocaleBase)
  125.     {
  126.         CloseLibrary(LocaleBase);
  127.  
  128.         LocaleBase = NULL;
  129.     }
  130. }
  131.  
  132.     /* LanguageCheck():
  133.      *
  134.      *    Checks to see if the currently selected language
  135.      *    is english.
  136.      */
  137.  
  138. VOID
  139. LanguageCheck()
  140. {
  141.     if(Locale && Catalog)
  142.     {
  143.         if(Locale -> loc_LanguageName)
  144.         {
  145.             if(!Stricmp(Locale -> loc_LanguageName,"english.language"))
  146.                 English = TRUE;
  147.             else
  148.                 English = FALSE;
  149.         }
  150.         else
  151.             English = FALSE;
  152.     }
  153.     else
  154.         English = TRUE;
  155. }
  156.  
  157.     /* LocaleSeconds(WORD Seconds):
  158.      *
  159.      *    Return seconds in proper format.
  160.      */
  161.  
  162. STRPTR __regargs
  163. LocaleSeconds(WORD Seconds)
  164. {
  165.     STATIC UBYTE Time[10];
  166.  
  167.     if(Locale)
  168.         SPrintf(Time,"%2lD%s%02lD",Seconds / 100,Locale -> loc_DecimalPoint,Seconds % 100);
  169.     else
  170.         SPrintf(Time,"%2ld.%02ld",Seconds / 100,Seconds % 100);
  171.  
  172.     return(Time);
  173. }
  174.  
  175.     /* SmallCurrency():
  176.      *
  177.      *    Support function for the rates control panel, returns a formatted
  178.      *    string to contain a string like "cents/unit".
  179.      */
  180.  
  181. STRPTR
  182. SmallCurrency()
  183. {
  184.     STATIC UBYTE Buffer[30];
  185.  
  186.     if(Locale)
  187.         SPrintf(Buffer,LocaleString(MSG_RATEPANEL_PAY_PER_UNIT_GAD),Locale -> loc_MonSmallCS);
  188.     else
  189.         SPrintf(Buffer,LocaleString(MSG_RATEPANEL_PAY_PER_UNIT_GAD),"Pay");
  190.  
  191.     return(Buffer);
  192. }
  193.  
  194.     /* InsertGrouping(STRPTR Buffer,STRPTR GroupData,STRPTR GroupSeparator):
  195.      *
  196.      *    Tricky stuff, folks! This beauty will insert grouping characters
  197.      *    into a readily-prepared string buffer filled with numeric
  198.      *    contents. It takes the group separator tokens and group separator
  199.      *    strings into account.
  200.      */
  201.  
  202. VOID __regargs
  203. InsertGrouping(STRPTR Buffer,STRPTR GroupData,STRPTR GroupSeparator)
  204. {
  205.     UBYTE    LocalBuffer[80];    // Sufficient, but too large
  206.     STRPTR    Index;
  207.     LONG    i,j,SeparatorSize;
  208.     WORD    Count;            // How many characters per group
  209.     BOOL    RepeatGroupCount;    // Keep repeating group size until end
  210.  
  211.         // Set up for the first group
  212.  
  213.     switch(*GroupData)
  214.     {
  215.         case 0:            // Repeat current grouping scheme until end
  216.         case 255:        // No further grouping is to be performed
  217.  
  218.             Count = 0;
  219.  
  220.             break;
  221.  
  222.         default:        // Initial group size
  223.  
  224.             RepeatGroupCount = FALSE;
  225.  
  226.             Count = *GroupData++;
  227.  
  228.             break;
  229.     }
  230.  
  231.         // Check the size of the group separator string
  232.  
  233.     if((SeparatorSize = strlen(GroupSeparator) - 1) < 1)
  234.         Count = 0;
  235.  
  236.         // That where we'll start
  237.  
  238.     Index = LocalBuffer;
  239.  
  240.         // Build the string back to front, we will reverse it later
  241.  
  242.     for(i = strlen(Buffer) - 1, j = 1 ; i >= 0 ; i--, j++)
  243.     {
  244.             // Pick up the next number character
  245.  
  246.         *Index++ = Buffer[i];
  247.  
  248.             // Are we to insert the grouping characters here?
  249.  
  250.         if(Count && j == Count)
  251.         {
  252.             LONG k;
  253.  
  254.                 // Insert the grouping characters
  255.  
  256.             for(k = SeparatorSize ; k >= 0 ; k--)
  257.                 *Index++ = GroupSeparator[k];
  258.  
  259.                 // Reset the group size counter
  260.  
  261.             j = 0;
  262.  
  263.                 // Pick up the next grouping token?
  264.  
  265.             if(!RepeatGroupCount)
  266.             {
  267.                     // Ok, what kind of token is it?
  268.  
  269.                 switch(*GroupData)
  270.                 {
  271.                     case 0:        // Repeat current grouping scheme
  272.  
  273.                         RepeatGroupCount = TRUE;
  274.                         break;
  275.  
  276.                     case 255:    // Perform no further grouping
  277.  
  278.                         Count = 0;
  279.                         break;
  280.  
  281.                     default:    // New group size
  282.  
  283.                         Count = *GroupData++;
  284.                         break;
  285.                 }
  286.             }
  287.         }
  288.     }
  289.  
  290.         // Look how long the resulting string is
  291.  
  292.     j = (LONG)((ULONG)Index - (ULONG)LocalBuffer) - 1;
  293.  
  294.         // Copy it back
  295.  
  296.     Index = Buffer;
  297.  
  298.         // Reverse the order of characters while copying
  299.  
  300.     for(i = j ; i >= 0 ; i--)
  301.         *Index++ = LocalBuffer[i];
  302.  
  303.         // Provide null-termination
  304.  
  305.     *Index = 0;
  306. }
  307.  
  308. VOID __regargs
  309. ConvertMonetaryQuantity(LONG Units,STRPTR Destination,BOOL UseCurrency)
  310. {
  311.     UBYTE    IntegerBuffer[80];    // Sufficient, but too large
  312.  
  313.     STRPTR    SignText,        // Signed/unsigned quantity text
  314.         SpaceText,        // Currency/number separation
  315.         Currency;        // The name of the currency
  316.     UBYTE    SpaceSep,        // A space separates currency and quantity?
  317.         SignPos,        // Where to place the sign text
  318.         CSPos;            // Where to place the currency text
  319.     BYTE    Sign;            // Negative or positive quantity?
  320.  
  321.         // Negative quantity?
  322.  
  323.     if(Units < 0)
  324.     {
  325.         Sign = -1;
  326.  
  327.         Units = -Units;
  328.     }
  329.     else
  330.         Sign = 1;
  331.  
  332.         // Does this currency sport a fractional smaller currency?
  333.  
  334.     if(Locale -> loc_MonFracDigits)
  335.     {
  336.         UBYTE    NumberBuffer[5],
  337.             FractionBuffer[40];
  338.         LONG    Integer,
  339.             Fraction,
  340.             Scale;
  341.         WORD    i;
  342.  
  343.             // Prepare the formatting string
  344.  
  345.         SPrintf(NumberBuffer,"%%0%ldld",Locale -> loc_MonFracDigits);
  346.  
  347.             // Turn the number of fractional digits into a power of ten
  348.  
  349.         for(i = 0, Scale = 1 ; i < Locale -> loc_MonFracDigits ; i++)
  350.             Scale *= 10;
  351.  
  352.             // Split the quantity in integer and fractional part
  353.  
  354.         Integer        = Units / Scale;
  355.         Fraction    = Units % Scale;
  356.  
  357.             // Build the integer text
  358.  
  359.         SPrintf(IntegerBuffer,"%ld",Integer);
  360.  
  361.         InsertGrouping(IntegerBuffer,Locale -> loc_MonGrouping,Locale -> loc_MonGroupSeparator);
  362.  
  363.             // Build the fractional text
  364.  
  365.         SPrintf(FractionBuffer,NumberBuffer,Fraction);
  366.  
  367.         InsertGrouping(FractionBuffer,Locale -> loc_MonFracGrouping,Locale -> loc_MonFracGroupSeparator);
  368.  
  369.             // Add the monetary decimal point
  370.  
  371.         strcat(IntegerBuffer,Locale -> loc_MonDecimalPoint);
  372.  
  373.             // Add the fractional part
  374.  
  375.         strcat(IntegerBuffer,FractionBuffer);
  376.     }
  377.     else
  378.     {
  379.             // Build the integer text
  380.  
  381.         SPrintf(IntegerBuffer,"%ld",Units);
  382.  
  383.         InsertGrouping(IntegerBuffer,Locale -> loc_MonGrouping,Locale -> loc_MonGroupSeparator);
  384.     }
  385.  
  386.         // Pick up the appropriate formatting parameters
  387.  
  388.     if(Sign < 0)
  389.     {
  390.         SignText    = Locale -> loc_MonNegativeSign;
  391.         SpaceSep    = Locale -> loc_MonNegativeSpaceSep;
  392.         SignPos        = Locale -> loc_MonNegativeSignPos;
  393.         CSPos        = Locale -> loc_MonNegativeCSPos;
  394.     }
  395.     else
  396.     {
  397.         SignText    = Locale -> loc_MonPositiveSign;
  398.         SpaceSep    = Locale -> loc_MonPositiveSpaceSep;
  399.         SignPos        = Locale -> loc_MonPositiveSignPos;
  400.         CSPos        = Locale -> loc_MonPositiveCSPos;
  401.     }
  402.  
  403.         // Are we to use the currency symbol?
  404.  
  405.     if(UseCurrency)
  406.     {
  407.             // Pick up the currency text
  408.  
  409.         Currency = Locale -> loc_MonCS;
  410.  
  411.             // Take care of the separation information
  412.  
  413.         if(SpaceSep == SS_NOSPACE)
  414.             SpaceText = "";
  415.         else
  416.             SpaceText = " ";
  417.     }
  418.     else
  419.         Currency = SpaceText = "";
  420.  
  421.         // Now merge all the information into one single string
  422.  
  423.     if(CSPos == CSP_PRECEDES)
  424.     {
  425.         switch(SignPos)
  426.         {
  427.             case SP_PARENS:
  428.  
  429.                 // Currency (Space) Sign Value
  430.                 SPrintf(Destination,"(%s%s%s%s)",Currency,SpaceText,SignText,IntegerBuffer);
  431.                 break;
  432.  
  433.             case SP_PREC_ALL:
  434.  
  435.                 // Sign Currency (Space) Value
  436.                 SPrintf(Destination,"%s%s%s%s",SignText,Currency,SpaceText,IntegerBuffer);
  437.                 break;
  438.  
  439.             case SP_SUCC_ALL:
  440.  
  441.                 // Currency (Space) Value Sign
  442.                 SPrintf(Destination,"%s%s%s%s",Currency,SpaceText,IntegerBuffer,SignText);
  443.                 break;
  444.  
  445.             case SP_PREC_CURR:
  446.  
  447.                 // Sign Currency (Space) Value
  448.                 SPrintf(Destination,"%s%s%s%s",SignText,Currency,SpaceText,IntegerBuffer);
  449.                 break;
  450.  
  451.             case SP_SUCC_CURR:
  452.  
  453.                 // Currency Sign (Space) Value
  454.                 SPrintf(Destination,"%s%s%s%s",Currency,SignText,SpaceText,IntegerBuffer);
  455.                 break;
  456.         }
  457.     }
  458.     else
  459.     {
  460.         switch(SignPos)
  461.         {
  462.             case SP_PARENS:
  463.  
  464.                 // Sign Value (Space) Currency
  465.                 SPrintf(Destination,"(%s%s%s%s)",SignText,IntegerBuffer,SpaceText,Currency);
  466.                 break;
  467.  
  468.             case SP_PREC_ALL:
  469.  
  470.                 // Sign Value (Space) Currency
  471.                 SPrintf(Destination,"%s%s%s%s",SignText,IntegerBuffer,SpaceText,Currency);
  472.                 break;
  473.  
  474.             case SP_SUCC_ALL:
  475.  
  476.                 // Value (Space) Currency Sign
  477.                 SPrintf(Destination,"%s%s%s%s",IntegerBuffer,SpaceText,Currency,SignText);
  478.                 break;
  479.  
  480.             case SP_PREC_CURR:
  481.  
  482.                 // Value (Space) Sign Currency
  483.                 SPrintf(Destination,"%s%s%s%s",IntegerBuffer,SpaceText,SignText,Currency);
  484.                 break;
  485.  
  486.             case SP_SUCC_CURR:
  487.  
  488.                 // Value (Space) Currency Sign
  489.                 SPrintf(Destination,"%s%s%s%s",IntegerBuffer,SpaceText,Currency,SignText);
  490.                 break;
  491.         }
  492.     }
  493. }
  494.  
  495.     /* CreateSum(LONG Quantity):
  496.      *
  497.      *    Create a string containing a monetary quantity formatted
  498.      *    according to the current locale rules.
  499.      */
  500.  
  501. STRPTR __regargs
  502. CreateSum(LONG Quantity,BYTE UseCurrency)
  503. {
  504.     STATIC UBYTE Buffer[100];
  505.  
  506.     if(Locale)
  507.         ConvertMonetaryQuantity(Quantity,Buffer,UseCurrency);
  508.     else
  509.         SPrintf(Buffer,"%ld.%02ld",Quantity / 100,Quantity % 100);
  510.  
  511.     return(Buffer);
  512. }
  513.  
  514.     /* LocalizeString(STRPTR *Strings,WORD From,WORD To):
  515.      *
  516.      *    Localize an array of strings.
  517.      */
  518.  
  519. VOID __regargs
  520. LocalizeString(STRPTR *Strings,WORD From,WORD To)
  521. {
  522.     WORD i,j;
  523.  
  524.     for(i = From, j = 0 ; i <= To ; i++)
  525.     {
  526.         if(!Strings[j])
  527.             Strings[j++] = LocaleString(i);
  528.     }
  529. }
  530.  
  531.     /* LocalizeStringTable(STRPTR *Strings,LONG *Table)
  532.      *
  533.      *    Localize an array of strings.
  534.      */
  535.  
  536. VOID __regargs
  537. LocalizeStringTable(STRPTR *Strings,LONG *Table)
  538. {
  539.     while(*Table != -1)
  540.         *Strings++ = LocaleString(*Table++);
  541.  
  542.     *Strings = NULL;
  543. }
  544.  
  545.     /* LocalizeMenu(struct NewMenu *Menu,WORD From):
  546.      *
  547.      *    Localize a NewMenu definition.
  548.      */
  549.  
  550. VOID __regargs
  551. LocalizeMenu(struct NewMenu *Menu,WORD From)
  552. {
  553.     STRPTR Label,Shortcut;
  554.  
  555.         while(Menu -> nm_Type != NM_END)
  556.     {
  557.         Shortcut = LocaleString(From);
  558.  
  559.         if(Shortcut[0] && !Shortcut[1])
  560.             Label = Shortcut + 2;
  561.         else
  562.         {
  563.             Label        = Shortcut;
  564.             Shortcut    = NULL;
  565.         }
  566.  
  567.         switch(Menu -> nm_Type)
  568.         {
  569.             case NM_TITLE:
  570.  
  571.                 Menu -> nm_Label = Label;
  572.  
  573.                 From++;
  574.  
  575.                 break;
  576.  
  577.             case NM_ITEM:
  578.             case NM_SUB:
  579.  
  580.                 if(Menu -> nm_Label != NM_BARLABEL)
  581.                 {
  582.                     Menu -> nm_Label    = Label;
  583.                     Menu -> nm_CommKey    = Shortcut;
  584.  
  585.                     From++;
  586.                 }
  587.  
  588.                 break;
  589.         }
  590.  
  591.         Menu++;
  592.     }
  593. }
  594.  
  595. VOID __regargs
  596. LocalizeMenuTable(struct NewMenu *Menu,LONG *Table)
  597. {
  598.     STRPTR    Label,Shortcut;
  599.     LONG    From = 0;
  600.  
  601.         while(Menu -> nm_Type != NM_END)
  602.     {
  603.         Shortcut = LocaleString(Table[From]);
  604.  
  605.         if(Shortcut[0] && !Shortcut[1])
  606.             Label = Shortcut + 2;
  607.         else
  608.         {
  609.             Label        = Shortcut;
  610.             Shortcut    = NULL;
  611.         }
  612.  
  613.         switch(Menu -> nm_Type)
  614.         {
  615.             case NM_TITLE:
  616.  
  617.                 Menu -> nm_Label = Label;
  618.  
  619.                 From++;
  620.  
  621.                 break;
  622.  
  623.             case NM_ITEM:
  624.             case NM_SUB:
  625.  
  626.                 if(Menu -> nm_Label != NM_BARLABEL)
  627.                 {
  628.                     Menu -> nm_Label    = Label;
  629.                     Menu -> nm_CommKey    = Shortcut;
  630.  
  631.                     From++;
  632.                 }
  633.  
  634.                 break;
  635.         }
  636.  
  637.         Menu++;
  638.     }
  639. }
  640.  
  641.     /* LocaleString(LONG ID):
  642.      *
  643.      *    Obtain a string from the translation pool.
  644.      */
  645.  
  646. STRPTR __regargs
  647. LocaleString(LONG ID)
  648. {
  649.     STRPTR Builtin;
  650.  
  651.     if(ID < NumAppStrings && AppStrings[ID] . cca_ID == ID)
  652.         Builtin = AppStrings[ID] . cca_Str;
  653.     else
  654.     {
  655.         LONG i;
  656.  
  657.         Builtin = "";
  658.  
  659.         for(i = 0 ; i < NumAppStrings ; i++)
  660.         {
  661.             if(AppStrings[i] . cca_ID == ID)
  662.             {
  663.                 Builtin = AppStrings[i] . cca_Str;
  664.  
  665.                 break;
  666.             }
  667.         }
  668.     }
  669.  
  670.     if(Catalog)
  671.     {
  672.         STRPTR String = GetCatalogStr(Catalog,ID,Builtin);
  673.  
  674.         if(String[0])
  675.             return(String);
  676.         else
  677.             return(Builtin);
  678.     }
  679.     else
  680.         return(Builtin);
  681. }
  682.  
  683. STRPTR __saveds __asm
  684. LocaleHookFunc(register __a0 struct Hook *Hook,register __a1 LONG ID)
  685. {
  686.     return(LocaleString(ID));
  687. }
  688.  
  689. STATIC LONG __saveds __asm
  690. FormatDateHookFunc(register __a0 struct Hook *Hook,register __a1 UBYTE Char)
  691. {
  692.     STRPTR String = Hook -> h_Data;
  693.  
  694.     *String++ = Char;
  695.  
  696.     Hook -> h_Data = String;
  697.  
  698.     return(TRUE);
  699. }
  700.  
  701.     /* FormatStamp():
  702.      *
  703.      *    Convert a date stamp into human readable
  704.      *    form by taking the current locale parameters
  705.      *    into account.
  706.      */
  707.  
  708. BOOLEAN __regargs
  709. FormatStamp(struct DateStamp *Stamp,STRPTR DateBuffer,STRPTR TimeBuffer,STRPTR BothBuffer,BOOLEAN SubstituteDay)
  710. {
  711.     struct DateStamp Now;
  712.  
  713.         // If no time stamp given, do with current time
  714.  
  715.     if(!Stamp)
  716.         DateStamp(Stamp = &Now);
  717.  
  718.         // Is the current locale available?
  719.  
  720.     if(Locale)
  721.     {
  722.         struct Hook LocalHook = {{NULL}, (HOOKFUNC)FormatDateHookFunc};
  723.  
  724.             // Combine date and time text?
  725.  
  726.         if(BothBuffer && !SubstituteDay)
  727.         {
  728.             LocalHook . h_Data = BothBuffer;
  729.  
  730.             FormatDate(Locale,Locale -> loc_DateTimeFormat,Stamp,&LocalHook);
  731.  
  732.             StripSpaces(BothBuffer);
  733.         }
  734.         else
  735.         {
  736.             UBYTE    LocalDateBuffer[40],
  737.                 LocalTimeBuffer[40];
  738.  
  739.                 // Provide storage space
  740.  
  741.             if(BothBuffer)
  742.             {
  743.                 DateBuffer = LocalDateBuffer;
  744.                 TimeBuffer = LocalTimeBuffer;
  745.             }
  746.  
  747.                 // Do we have a date buffer to fill?
  748.  
  749.             if(DateBuffer)
  750.             {
  751.                     // Are we to substitute the current day with
  752.                     // text such as today, yesterday, etc.?
  753.  
  754.                 if(SubstituteDay)
  755.                 {
  756.                     struct DateStamp    Today;
  757.                     STRPTR            String;
  758.  
  759.                         // Get the current time
  760.  
  761.                     DateStamp(&Today);
  762.  
  763.                         // Does the date refer to yesterday?
  764.  
  765.                     if(Stamp -> ds_Days == Today . ds_Days - 1)
  766.                         String = GetLocaleStr(Locale,YESTERDAYSTR);
  767.                     else
  768.                     {
  769.                             // Does the date refer to today?
  770.  
  771.                         if(Stamp -> ds_Days == Today . ds_Days)
  772.                             String = GetLocaleStr(Locale,TODAYSTR);
  773.                         else
  774.                         {
  775.                                 // Does the date refer to tomorrow?
  776.  
  777.                             if(Stamp -> ds_Days == Today . ds_Days + 1)
  778.                                 String = GetLocaleStr(Locale,TOMORROWSTR);
  779.                             else
  780.                             {
  781.                                 String        = NULL;
  782.                                 SubstituteDay    = NULL;
  783.                             }
  784.                         }
  785.                     }
  786.  
  787.                     if(String)
  788.                         strcpy(DateBuffer,String);
  789.                     else
  790.                         DateBuffer[0] = 0;
  791.                 }
  792.  
  793.                 if(!SubstituteDay)
  794.                 {
  795.                     LocalHook . h_Data = DateBuffer;
  796.  
  797.                     FormatDate(Locale,Locale -> loc_DateFormat,Stamp,&LocalHook);
  798.                 }
  799.  
  800.                 StripSpaces(DateBuffer);
  801.             }
  802.  
  803.             if(TimeBuffer)
  804.             {
  805.                 LocalHook . h_Data = TimeBuffer;
  806.  
  807.                 FormatDate(Locale,Locale -> loc_TimeFormat,Stamp,&LocalHook);
  808.  
  809.                 StripSpaces(TimeBuffer);
  810.             }
  811.  
  812.                 // Combine date and time
  813.  
  814.             if(BothBuffer)
  815.             {
  816.                 strcpy(BothBuffer,DateBuffer);
  817.                 strcat(BothBuffer," ");
  818.                 strcat(BothBuffer,TimeBuffer);
  819.             }
  820.         }
  821.     }
  822.     else
  823.     {
  824.         struct DateTime    DateTime;
  825.         UBYTE        LocalDateBuffer[40],
  826.                 LocalTimeBuffer[40];
  827.  
  828.             // Provide storage space
  829.  
  830.         if(BothBuffer)
  831.         {
  832.             DateBuffer = LocalDateBuffer;
  833.             TimeBuffer = LocalTimeBuffer;
  834.         }
  835.  
  836.             // No locale, so we will use dos.library instead.
  837.  
  838.         CopyMem(Stamp,&DateTime . dat_Stamp,sizeof(struct DateStamp));
  839.  
  840.         DateTime . dat_Format    = FORMAT_DOS;
  841.         DateTime . dat_Flags    = SubstituteDay ? DTF_SUBST : NULL;
  842.         DateTime . dat_StrDay    = NULL;
  843.         DateTime . dat_StrDate    = DateBuffer;
  844.         DateTime . dat_StrTime    = TimeBuffer;
  845.  
  846.         if(!DateToStr(&DateTime))
  847.             return(FALSE);
  848.  
  849.         if(DateBuffer)
  850.             StripSpaces(DateBuffer);
  851.  
  852.         if(TimeBuffer)
  853.             StripSpaces(TimeBuffer);
  854.  
  855.             // Combine date and time
  856.  
  857.         if(BothBuffer)
  858.         {
  859.             strcpy(BothBuffer,DateBuffer);
  860.             strcat(BothBuffer," ");
  861.             strcat(BothBuffer,TimeBuffer);
  862.         }
  863.     }
  864.  
  865.     return(TRUE);
  866. }
  867.  
  868.     /* FormatTime(STRPTR Buffer,LONG Hours,LONG Minutes,LONG Seconds):
  869.      *
  870.      *    Given hours, minutes and seconds, format this data into
  871.      *    a human-readable string.
  872.      */
  873.  
  874. VOID __regargs
  875. FormatTime(STRPTR Buffer,LONG Hours,LONG Minutes,LONG Seconds)
  876. {
  877.     if(Locale)
  878.     {
  879.         struct Hook LocalHook = {{NULL}, (HOOKFUNC)FormatDateHookFunc};
  880.  
  881.         struct DateStamp Stamp;
  882.  
  883.         Stamp . ds_Days        = 0;
  884.         Stamp . ds_Minute    = Hours * 60 + Minutes;
  885.         Stamp . ds_Tick        = MAX(0,Seconds) * TICKS_PER_SECOND;
  886.  
  887.         LocalHook . h_Data = Buffer;
  888.  
  889.         if(Seconds < 0)
  890.             FormatDate(Locale,Locale -> loc_ShortTimeFormat,&Stamp,&LocalHook);
  891.         else
  892.             FormatDate(Locale,Locale -> loc_TimeFormat,&Stamp,&LocalHook);
  893.     }
  894.     else
  895.     {
  896.         if(Seconds < 0)
  897.             SPrintf(Buffer,"%02ld:%02ld",Hours,Minutes);
  898.         else
  899.             SPrintf(Buffer,"%02ld:%02ld:%02ld",Hours,Minutes,Seconds);
  900.     }
  901. }
  902.